deploy: move live updates to git-free /opt release snapshots#56
Conversation
Greptile SummaryThis PR decouples live production updates from mutable git checkouts by introducing git-free release snapshots under
Confidence Score: 4/5
Important Files Changed
Flowchartflowchart TD
A["baudbot update"] --> B["Clone into /tmp/baudbot-update.*"]
B --> C{"Preflight checks?"}
C -->|Pass| D["Publish git-free snapshot to /opt/baudbot/releases/<sha>"]
C -->|Fail| X1["❌ Abort — current unchanged"]
D --> E["Deploy from snapshot (bin/deploy.sh)"]
E -->|Fail| X2["❌ Abort — current unchanged, release preserved"]
E -->|Pass| F["Restart + health check"]
F -->|Fail| X3["❌ Abort — current unchanged"]
F -->|Pass| G["Atomic symlink swap: previous → old current, current → new release"]
G --> H["Update CLI link /usr/local/bin/baudbot → /opt/baudbot/current/bin/baudbot"]
H --> I["✅ Update complete"]
J["baudbot rollback previous"] --> K["Resolve previous symlink"]
K --> L["Deploy from target snapshot"]
L -->|Fail| X4["❌ Abort — current unchanged"]
L -->|Pass| M["Restart + health check"]
M -->|Pass| N["Atomic symlink swap: previous ↔ current"]
N --> O["✅ Rollback complete"]
Last reviewed commit: fcf2c5a |
| env_tmp=$(mktemp) | ||
| cp "$ADMIN_CONFIG" "$env_tmp" | ||
| chmod 644 "$env_tmp" |
There was a problem hiding this comment.
Secrets briefly world-readable in /tmp
The temp file holding the admin .env (API keys, tokens) is widened to 644 (world-readable) before as_agent copies it. While the window is small, any process on the system can read the secrets during this interval. Since this is a security-hardened environment, consider narrowing access to just the agent's group:
| env_tmp=$(mktemp) | |
| cp "$ADMIN_CONFIG" "$env_tmp" | |
| chmod 644 "$env_tmp" | |
| env_tmp=$(mktemp) | |
| cp "$ADMIN_CONFIG" "$env_tmp" | |
| chgrp "$AGENT_USER" "$env_tmp" | |
| chmod 640 "$env_tmp" |
This preserves the intent (agent can read the staged file) without exposing secrets to all users.
Prompt To Fix With AI
This is a comment left during a code review.
Path: bin/deploy.sh
Line: 292:294
Comment:
**Secrets briefly world-readable in /tmp**
The temp file holding the admin `.env` (API keys, tokens) is widened to `644` (world-readable) before `as_agent` copies it. While the window is small, any process on the system can read the secrets during this interval. Since this is a security-hardened environment, consider narrowing access to just the agent's group:
```suggestion
env_tmp=$(mktemp)
cp "$ADMIN_CONFIG" "$env_tmp"
chgrp "$AGENT_USER" "$env_tmp"
chmod 640 "$env_tmp"
```
This preserves the intent (agent can read the staged file) without exposing secrets to all users.
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
Good catch — fixed in 7c496bd. I removed the temp-file staging flow entirely and now stream the admin config directly into the agent-owned target (as_agent ... cat > ~/.config/.env), then chmod 600. This avoids any world-readable /tmp window for secrets.
| GIT_SHA_SHORT="" | ||
| GIT_BRANCH="" | ||
|
|
||
| if cd "$BAUDBOT_SRC" && git rev-parse HEAD >/dev/null 2>&1; then |
There was a problem hiding this comment.
cd changes CWD as a side effect
The bare cd "$BAUDBOT_SRC" here mutates the working directory of the main script process. While subsequent commands use absolute paths so this doesn't cause a functional bug, it's fragile — any future relative-path usage would break silently. Consider wrapping the git check in a subshell to avoid the side effect:
| if cd "$BAUDBOT_SRC" && git rev-parse HEAD >/dev/null 2>&1; then | |
| if (cd "$BAUDBOT_SRC" && git rev-parse HEAD >/dev/null 2>&1); then |
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Prompt To Fix With AI
This is a comment left during a code review.
Path: bin/deploy.sh
Line: 326:326
Comment:
**`cd` changes CWD as a side effect**
The bare `cd "$BAUDBOT_SRC"` here mutates the working directory of the main script process. While subsequent commands use absolute paths so this doesn't cause a functional bug, it's fragile — any future relative-path usage would break silently. Consider wrapping the git check in a subshell to avoid the side effect:
```suggestion
if (cd "$BAUDBOT_SRC" && git rev-parse HEAD >/dev/null 2>&1); then
```
<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
Addressed in 7c496bd. Updated the git-probe condition to use a subshell: (cd "$BAUDBOT_SRC" && git rev-parse ...) so script CWD is not mutated as a side effect.
|
Addressed both review items in commit
Validation rerun:
Both pass (10/10 overall). |
Summary
This PR decouples production operations from mutable developer checkouts by moving live updates to git-free release snapshots under
/opt/baudbot.Instead of
baudbot updatedoinggit pullin-place, updates now:/tmp/baudbot-update.*/opt/baudbot/releases/<sha>(no.git)/opt/baudbot/currentonly after successful deploy/restart/health checksIt also adds first-class rollback (
baudbot rollback previous|<sha>) and updates install/setup/docs/CI checks for the new model.Why
Current behavior couples live update operations to a mutable repo path and local working state. This PR gives us:
currentmutation on failed preflight/deploy)Key changes
New scripts
bin/update-release.shbaudbot-release.json)current/previoussymlink managementbin/rollback-release.shpreviousor explicit SHA/prefixcurrent/previousCLI
bin/baudbotupdatenow delegates toupdate-release.shrollbackcommandDeploy metadata compatibility
bin/deploy.shbaudbot-release.jsonwhen deploying from git-free snapshotsInstall/setup/uninstall wiring
setup.shandinstall.shupdate-release.sh(not direct mutable checkout deployment)bin/uninstall.sh/opt/baudbotrelease treeCI checks and tests
New tests:
bin/update-release.test.shbin/rollback-release.test.shbin/test.shDroplet setup scripts now verify:
/usr/local/bin/baudbotresolves into/opt/baudbot/releases/.../bin/baudbot/opt/baudbot/currentexists/opt/baudbot/releases/*are git-freeDocs
README.md,CONFIGURATION.md,AGENTS.mdfor:/optrelease architectureValidation performed
Local
bash bin/test.sh→ 10/10 passedbash bin/update-release.test.sh→ 3/3 passedbash bin/rollback-release.test.sh→ 3/3 passedDigitalOcean acceptance (real droplets)
Validated on both:
217410218For each distro:
install.sh/optrelease bootstrap successful10/10)baudbot update --skip-preflight --skip-restartadvanced to new release SHAbaudbot rollback previous --skip-restartreturned to prior SHA.gitunder/opt/baudbot/releasesbaudbot start/stopsmoke checks passed (active→inactive)All CI test droplets used for verification were destroyed after validation.
Issues found during validation (and fixed)
Root cloning from local admin checkout hit git
safe.directoryprotections.Config deploy path in update/rollback did not consistently preserve
BAUDBOT_CONFIG_USER.Both fixes were re-tested locally and on droplets.
Operator impact
sudo baudbot updatesudo baudbot rollback previousbaudbot deploy) remains available.